home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Diamond Collection / The Diamond Collection (Software Vault)(Digital Impact).ISO / cdr40 / x1j4_src.zip / TNL4.C < prev    next >
Text File  |  1995-03-01  |  32KB  |  784 lines

  1. /*****************************************************************************/
  2. /*                                              */
  3. /*                                         */
  4. /*    *****              *****                      */
  5. /*     *****            *****                         */
  6. /*       *****          *****                         */
  7. /*         *****        *****                         */
  8. /*  ***************      ***************                     */
  9. /*  *****************    *****************                     */
  10. /*  ***************      ***************                     */
  11. /*         *****        *****       TheNet                    */
  12. /*       *****          *****       Portable. Compatible.         */
  13. /*     *****            *****       Public Domain             */
  14. /*    *****              *****    NORD><LINK                  */
  15. /*                                         */
  16. /* This software is public domain ONLY for non commercial use                */
  17. /*                                                                           */
  18. /*                                         */
  19. /*****************************************************************************/
  20.  
  21. /* Level 4, Transport
  22. /* Version 1.01                                     */
  23. /* Hans Georg Giese, DF2AU, Hinter dem Berge 5, 3300 Braunschweig         */
  24. /* 01-MAY-88                                     */
  25. /* Modified G8KBB April 1991 
  26.  *     added bank switching version
  27.  *     use of register keyword for code size
  28.  *     use all.h header file
  29.  *     added auditing of level 4 connections optionally on MANAGED
  30.  *     remove unnecessary '== 1' and similar code
  31.  *     add ip router link to l4rx()
  32.  *     add stats gathering
  33.  *     add parameter to splcpy to support MTU changes to show no splitting
  34.  *
  35.  * September 1993 - released as TheNet X-1J
  36.  *
  37.  * extend L4 rx ACL to bar user callsign as well as node callsign
  38.  */
  39.  
  40. #include "all.h"
  41. #include "tntyp.h"        /* Definition der Typen                 */
  42. #ifdef BANKED
  43. #define EXTERN extern
  44. #else
  45. #define EXTERN
  46. #endif
  47. #include "tnl4v.h"
  48. #include "tnl4e.h"        /* Externe Definitionen                 */
  49.  
  50. #ifdef MANAGED
  51. extern char L4audit[];
  52. #endif
  53.  
  54. /*---------------------------------------------------------------------------*/
  55. VOID    initl4()            /* Level 4 initialisieren         */
  56.  {
  57.   register unsigned cnt;        /* Sratch Zaehler             */
  58.  
  59.   inithd(&l4rxfl);            /* Liste fuer empfangene Frames         */
  60.  
  61.   for (cnt = NUMCIR, cirpoi = cirtab;    /* gesamte Circuit Tabelle         */
  62.        cnt != 0;                    /* bearbeiten                 */
  63.        --cnt, ++cirpoi)
  64.    {
  65.     cirpoi->state3 =            /* Eintrag ist leer             */
  66.     cirpoi->numrx  =            /* keine Frames empfangen         */
  67.     cirpoi->numtx  = 0;            /* keine Frames zu senden         */
  68.     cirpoi->fragme = NULL;        /* kein Frame Fragment da         */
  69.     inithd(&cirpoi->mbhdrx);        /* Empfangskette ist leer         */
  70.     inithd(&cirpoi->mbhdtx);        /* Sendekette ist leer             */
  71.     inithd(&cirpoi->mbhdos);        /* Kette "ausser Reihenfolge" leer   */
  72.    }
  73.   if (! iswarm())            /* im Kaltstart Standardwerte         */
  74.    {
  75.     tratou = DEFTTO;            /* Timeout                 */
  76.     tratri = DEFTTR;            /* Versuche                 */
  77.     traack = DEFTAC;            /* ACK Wartezeit             */
  78.     trabsy = DEFTBS;            /* Busy Wartezeit             */
  79.     trawir = DEFTWI;            /* Fenstergroesse             */
  80.    }
  81. }
  82.  
  83. /*---------------------------------------------------------------------------*/
  84. VOID    l4serv()        /* Level 4 Service                 */
  85.   {
  86.   l4tx();            /* Frames senden                 */
  87.   l4rx();            /* Frames empfangen                 */
  88.   l4rest();            /* sonstige Funktionen                 */
  89.   }
  90.  
  91. /*---------------------------------------------------------------------------*/
  92. VOID    l4tx()            /* Frames senden                 */
  93.   {
  94.   register unsigned unack;    /* unbestaetigte Frames                 */
  95.   register unsigned cnt;    /* Sratch Zaehler                 */
  96.   register mhtyp *nxtfra;    /* naechstes Frame                 */
  97.   unsigned isweg;        /* schon gesendete Frames             */
  98.  
  99.   for (cnt = 0, cirpoi = cirtab;/* gesamte Circuittabelle             */
  100.        cnt < NUMCIR;
  101.        ++cnt, ++cirpoi) {
  102.     if ((cirpoi->state3 == 2)    /* Eintrag ist connected             */
  103.       && (!(cirpoi->l4flag & 0x20)) /* und Partner nicht choked             */
  104.       && ((unack = (cirpoi->l4vs - cirpoi->l4rxvs) & 0xff) < cirpoi->numtx)
  105.       && (unack < cirpoi->window)) { /* Fenstergroesse nicht erreicht         */
  106.       for (isweg = 0, nxtfra = (mhtyp *) cirpoi->mbhdtx.lnext; /* neue Frames*/
  107.            isweg < unack;    /* schon gesendete offene Frames uebergehen  */
  108.            ++isweg, nxtfra = (mhtyp *) nxtfra->link.lnext);
  109.       do {
  110.         nxtfra->l4trie = 0;    /* Versuche := 0                 */
  111.         sndfrm(cirpoi->l4vs++, nxtfra); /* naechstes Frame senden         */
  112.         nxtfra = (mhtyp *) nxtfra->link.lnext; /* vorruecken              */
  113.         }
  114.       while ((++unack < cirpoi->numtx) /* bis Ende der Kette             */
  115.         && (cirpoi->window > unack)); /* oder Fenstergroesse ueberschritten  */
  116.       }
  117.     }
  118.   }
  119.  
  120. /*---------------------------------------------------------------------------*/
  121. VOID    l4rx()            /* Frames empfangen                 */
  122.   {
  123.   char       usrcal[7];        /* Call des Users                 */
  124.   char       orgnod[7];        /* Call des absendenden Knotens             */
  125.   unsigned fenste;        /* Fenstergroesse                 */
  126.   register unsigned cnt;    /* Scratch Zaehler                 */
  127.   mhtyp       *antwor;        /* Antwort auf Frame                 */
  128.   register cirtyp   *cirent;        /* CIRTAB Eintrag des Users             */
  129.   register mhtyp *nxtfra;    /* naechstes Frame                 */
  130.  
  131.   while ((nxtfra = (mhtyp *) l4rxfl.lnext) != (mhtyp *) &l4rxfl.lnext) {
  132. #ifdef STATSCMD
  133.     L4RXCNT[0]++;        /* bump received L4 packet count */
  134. #endif
  135.     unlink(nxtfra);        /* Frame aus Kette loesen             */
  136.     if ((nxtfra->putcnt - nxtfra->getcnt) >= 5) { /* lang genug?         */
  137.       l4hdr0 = getchr(nxtfra);    /* Header holen                     */
  138.       l4hdr1 = getchr(nxtfra);
  139.       l4hdr2 = getchr(nxtfra);
  140.       l4hdr3 = getchr(nxtfra);
  141.       if (((l4opco = getchr(nxtfra)) & 0x07) != 0x01) { /* CONREQ immer gut  */
  142.         if ((l4hdr0 < NUMCIR)    /* Index im Bereich?                 */
  143.           && ((cirpoi = &cirtab[l4hdr0])->state3 != 0)
  144.           && (cirpoi->ideige == l4hdr1)) {
  145.           l4pidx = cirpoi->idxpar;
  146.           l4pcid = cirpoi->idpart;
  147.           }
  148. #ifdef IPROUTE
  149.         /* if the frame appears to be an IP frame encapsulated in
  150.          * a netrom frame, then link it to the ip receive list
  151.          */
  152.         else if( l4opco == NR4_OP_PID &&
  153.                  l4hdr0 == NR_PROTO_IP &&
  154.                  l4hdr1 == NR_PROTO_IP )
  155.         {
  156.           nxtfra->pid = PID_IP;
  157.           relink( nxtfra, iprxfl.lprev );
  158.           continue;
  159.         }
  160. #endif
  161.         else {            /* schlechter Header                 */
  162.           dealmb(nxtfra);    /* Frame vernichten                 */
  163.           continue;
  164.           }
  165.         }
  166.       switch (l4opco & 0x07) {    /* ueber Opcode verzweigen             */
  167. /*=============================*/
  168. case 1:                /* Connect Request                 */
  169.   if (((nxtfra->putcnt - nxtfra->getcnt) >= 15) /* Frame lang genug?         */
  170.     && ((fenste = getchr(nxtfra) & 0xff) != 0)  /* Fenster muss sein         */
  171.     && (getfid(usrcal, nxtfra) /*== 1*/)        /* gueltiges Usercall         */
  172.     && (getfid(orgnod, nxtfra) /*== 1*/)        /* gueltiger Absender         */
  173.     && (iscall(orgnod) == TRUE))                /* Absender bekannt         */
  174.    {
  175.     l4pidx = l4hdr0;        /* Index und                     */
  176.     l4pcid = l4hdr1;        /* ID des Partners merken             */
  177.     for (cirent = 0, cnt = 0, cirpoi = cirtab; /* Circuit Tabelle absuchen   */
  178.          cnt < NUMCIR;
  179.          ++cnt, ++cirpoi) {
  180.       if (cirpoi->state3 != 0) {
  181.         if ((cmpid(usrcal, cirpoi->upcall) /*== 1*/)
  182.           && (cmpid(orgnod, cirpoi->downca) /*== 1*/)) {
  183.           if ((cirpoi->idxpar == l4hdr0)
  184.             && (cirpoi->idpart == l4hdr1)) break;
  185.             }
  186.           }
  187.       else {
  188.         if (cirent == 0) cirent = cirpoi;
  189.         }
  190.       }
  191.     if (cnt == NUMCIR) {    /* Ende der Tabelle erreicht?             */
  192.       if ((cirent != 0)        /* freien Platz gefunden?             */
  193. #ifdef ACL
  194.         && !( (acl_mask & ACL_BAR_L4_IC ) &&
  195.               ((acl_entry( usrcal ) & ACL_BAR_L4_IC ) ||
  196.                (acl_entry( orgnod ) & ACL_BAR_L4_IC )))
  197. #endif
  198.         && (fvalca(VCpar, usrcal) == 1)) { /* User Call gueltig?         */
  199.         cirpoi = cirent;    /* dann Eintrag nehmen                 */
  200.         cpyid(cirpoi->upcall, usrcal); /* Call eintragen             */
  201.         cpyid(cirpoi->downca, orgnod);
  202.         cirpoi->idxpar = l4hdr0; /* Parameter des Partnerknotens         */
  203.         cirpoi->idpart = l4hdr1;
  204.         cirpoi->ideige = random(); /* eigener ID                 */
  205.         cirpoi->l3node = despoi; /* Nachbar fuer den Eintrag             */
  206.         l2tol7(1, cirpoi, 4);    /* UA von Circuit nach zurueck             */
  207. #ifdef MANAGED
  208.         l4audit( AudCon );    /* audit the level 4 connect */
  209. #endif
  210.         cirpoi->tranoa = ininat; /* Timeout setzen                 */
  211.         }
  212.       else {            /* kein Platz - ungueltiges Call         */
  213.         l4ahd2 =        /* Antwort aufbauen                 */
  214.         l4ahd3 = 0;
  215.         l4aopc = 0x82;        /* Opcode = choked, Acknowledge             */
  216.         (antwor = gennhd())->l2lnk = (l2ltyp *) despoi; /* Antwort aufbauen  */
  217.         relink(antwor, l3txl.lprev); /* in Sendekette haengen             */
  218. #ifdef STATSCMD
  219.     L4TXCNT[0]++;        /* bump transmitted level 4 frame count */
  220. #endif
  221.         break;
  222.         }
  223.       }                               /* Eintrag gibt es schon         */
  224.     cirpoi->window = (fenste > trawir)? trawir : fenste;
  225.     clrcir();                           /* Eintrag initialisieren     */
  226.     l4ahd2 = (cirpoi - &cirtab[0]);
  227.     l4ahd3 = cirpoi->ideige;                   /* eigene Parameter setzen    */
  228.     l4aopc = 0x02;                       /* Antwort wird ACK         */
  229.     putchr(cirpoi->window, (antwor = gennhd()));
  230.     itol3(antwor);                       /* senden             */
  231.     cirpoi->state3 = 2;                           /* Status = connected         */
  232.     }
  233.   break;
  234.  
  235. /*=============================*/
  236. case 2:                /* Connect Acknowledge                 */
  237.   if (cirpoi->state3 == 1) {    /* macht nur Sinn, wenn Connect verlangt     */
  238.     if ((l4opco & 0x80) == 0) {    /* Partner darf nicht choked sein         */
  239.       if (nxtfra->getcnt < nxtfra->putcnt) { /* noch Info da?             */
  240.         cirpoi->window = getchr(nxtfra); /* holen                 */
  241.         cirpoi->idpart = l4hdr3; /* Partner Parameter setzen             */
  242.         cirpoi->idxpar = l4hdr2;
  243.         clrcir();        /* Eintrag initialisieren             */
  244.         l2tol7(1, cirpoi, 4);    /* Antwort ist UA vom Circuit             */
  245.         cirpoi->tranoa = ininat; /* Timeout setzen                 */
  246. #ifdef MANAGED
  247.         l4audit( AudConAcc );    /* audit connect acceptance */
  248. #endif
  249.         cirpoi->state3 +=1;    /* Status = connected                 */
  250.         }
  251.       }
  252.     else {            /* Partner ist choked                 */
  253.       l4nsta(3);        /* melden                     */
  254.       }
  255.     }
  256.   break;
  257.  
  258. /*=============================*/
  259. case 3:                /* Disconnect Request                 */
  260.   clr4rx(1);            /* restliche Info senden             */
  261. #ifdef MANAGED
  262.         l4audit( AudDisc );    /* audit level 4 disconnect */
  263. #endif
  264.   l4nsta(2);            /* nach oben melden                 */
  265.   l4ahd2 =
  266.   l4ahd3 = 0;            /* Antwort aufbauen                 */
  267.   l4aopc = 0x04;        /* Opcode = Disconnect ACK             */
  268.   itol3(gennhd());        /* Frame senden                     */
  269.   break;
  270.  
  271. /*=============================*/
  272. case 4:                /* Disconnect Acknowledge             */
  273.   if (cirpoi->state3 == 3) {    /* wurde DISC gegeben?                 */
  274.     l4nsta(2);            /* melden                     */
  275.     }
  276. #ifdef MANAGED
  277.         l4audit( AudDiscAcc );    /* audit level 4 disconnect acceptance */
  278. #endif
  279.   break;
  280.  
  281. /*=============================*/
  282. case 5:                /* Info Transfer                 */
  283.   if (cirpoi->state3 != 2)    /* nur wenn connected                 */
  284.     break;
  285.   chksts();            /* Status Info auswerten             */
  286.   if (((nxtfra->pid = (l4hdr2 - cirpoi->l4vr) & 0xff) < cirpoi->window)
  287.     && ((cirpoi->l4flag & 0x40) == 0)) { /* passt das Frame ins Fenster?     */
  288.     nxtfra->morflg = (l4opco & 0x20) != 0; /* fragmentiert?             */
  289.     if (nxtfra->pid == 0) {    /* passt Sequenz?                 */
  290.       takfrm(nxtfra);        /* Frame uebernehmen                 */
  291.       for (cnt = 1, antwor = (mhtyp *) cirpoi->mbhdos.lnext; /* Frames,      */
  292.         (mhtyp *) &(cirpoi->mbhdos) != antwor; /* die zu frueh kamen, absu-  */
  293.            antwor = (mhtyp *) antwor->link.lnext) { /* chen, ob nun passt    */
  294.         if ((antwor->pid -=cnt) == 0) { /* neuer Offset              */
  295.           nxtfra = (mhtyp *) antwor->link.lprev; /* Frame passt bei Offset 0 */
  296.           takfrm(unlink(antwor)); /* Frame aus Kette nehmen und verwerten    */
  297.           antwor = nxtfra;
  298.           ++cnt;        /* zulaessiger Offset eins weiter         */
  299.           }
  300.         }
  301.       cirpoi->l4rs = 0;    /* Antwort wird ACK                     */
  302. #ifdef MODIFIED
  303.       set_acktim();
  304. #else
  305.       cirpoi->acktim = traack;    /* ACK Timer laden                 */
  306. #endif
  307.       }
  308.     else {            /* Sequenz passt nicht                 */
  309.       for (antwor = (mhtyp *) cirpoi->mbhdos.lnext;;)
  310.        {                                /* in extra Kette haengen         */
  311.         if ((mhtyp *) &(cirpoi->mbhdos) == antwor) { /* Ende der Kette?         */
  312.           relink(nxtfra, cirpoi->mbhdos.lprev); /* dann einhaengen         */
  313.           break;
  314.           }
  315.         if (antwor->pid == nxtfra->pid) { /* Frame schon mal angekommen?     */
  316.           dealmb(nxtfra);    /* dann wegwerfen                 */
  317.           break;
  318.           }
  319.         if (antwor->pid > nxtfra->pid) { /* an passender Stelle einhaengen   */
  320.           relink(nxtfra, antwor->link.lprev);
  321.           break;
  322.           }
  323.         antwor = (mhtyp *) antwor->link.lnext; /* ein Frame weiter         */
  324.         }
  325.       if (cirpoi->l4rs == 0) {    /* Frame haengt in extra Kette             */
  326.         cirpoi->l4rs = 1;        /* wenn ACK gefordert war, nun NAK   */
  327. #ifdef MODIFIED
  328.         set_acktim();
  329. #else
  330.         cirpoi->acktim = traack;    /* ACK Wartezeit setzen             */
  331. #endif
  332.         }
  333.       }
  334.     continue;            /* naechstes Frame                 */
  335.     }
  336.   else                /* ungueltiges Frame oder selbst choked         */
  337. #ifdef MODIFIED
  338.     set_acktim();
  339. #else
  340.     cirpoi->acktim = traack;    /* Antwort hat Zeit                 */
  341. #endif
  342.   break;
  343.  
  344. /*=============================*/
  345. case 6:                /* Info Acknowledge                 */
  346.   if (cirpoi->state3 == 2)    /* nur sinnvoll, wenn connected             */
  347.     chksts();            /* enthaltene Statusinfo auswerten         */
  348.   break;
  349.  
  350. /*=============================*/
  351. default:            /* ungueltiger Opcode                 */
  352.   break;            /* uebergehen                     */
  353.  
  354. /*=============================*/
  355.       } }            /* Ende des Switch ueber Opcode             */
  356.     dealmb(nxtfra);        /* fertig bearbeitet, wegwerfen             */
  357.   } }
  358.  
  359. /*---------------------------------------------------------------------------*/
  360. VOID    l4rest()        /* diverse Level4 Funktionen             */
  361.   {
  362.   register unsigned cnt;    /* Scratch Zaehler                 */
  363.  
  364.   for (cnt = 0, cirpoi = cirtab; /* gesamte Tabelle bearbeiten             */
  365.        cnt < NUMCIR;
  366.        ++cnt, ++cirpoi) {
  367.     if (cirpoi->state3 == 2) {    /* nur fuer connectete Eintrage             */
  368.       if (((cirpoi->l4flag & 0x80) != 0) /* Abwurf gefordert             */
  369.         && (cirpoi->numtx == 0)) { /* und alles gesendet?             */
  370.         endcir();        /* Eintrag loeschen                 */
  371.         }
  372.       else {
  373.         clr4rx(0);        /* kein Abwurf gefordert: Info senden         */
  374.         if ((cirpoi->l4flag & 0x40) == 0) { /* selbst choked?             */
  375.           if ((nmbfre < 80)    /* nein: kein Platz im Buffer?             */
  376.             || (cirpoi->numrx >= conctl)) { /* oder zu viel empfangen?         */
  377.             cirpoi->l4flag |= 0x40; /* dann selbst choked setzen         */
  378.             cirpoi->l4rs = 0;    /* ACK als naechste Antwort             */
  379.             sndack();
  380.             }
  381.           }
  382.         else {
  383.           if ((nmbfre > 112)    /* selbst choked: wieder Platz im Buffer?    */
  384.             && (cirpoi->numrx < (conctl / 2))) { /* und Datenstau abgebaut?  */
  385.             cirpoi->l4flag &= 0xffbf; /* dann choked ruecksetzen         */
  386.             sndack();        /* melden                     */
  387.           } }
  388.       } }
  389.   } }
  390.  
  391. /*---------------------------------------------------------------------------*/
  392. VOID    trasrv()        /* Timerservice fuer Level 4             */
  393.   {
  394.   unsigned actsts;        /* Status des aktuellen Eintrages         */
  395.   unsigned fropen;        /* Zahl der unbestaetigten Frames         */
  396.   register unsigned cnt;    /* Scratch Zaehler                 */
  397.   register unsigned tosend;    /* Zahl der zu sendenden Frames             */
  398.   register mhtyp *nxtfra;    /* aktuelles Frame                 */
  399.  
  400.   for (cnt = 0, cirpoi = cirtab; /* gesamte Tabelle bearbeiten             */
  401.        cnt < NUMCIR;
  402.        ++cnt, ++cirpoi) {
  403.     if ((actsts = cirpoi->state3) != 0) { /* nur aktive Eintraege         */
  404.       if (cirpoi->traout != 0) { /* Timeout noch nicht abgelaufen         */
  405.         if (--cirpoi->traout == 0) { /* Timeout nun abgelaufen?             */
  406.           if (actsts == 2)    /* Status = connected?                 */
  407.             cirpoi->l4flag &= 0xffdf; /* nichts neues senden             */
  408.           else {        /* anderer Status:                 */
  409.             if (++cirpoi->l4try < tratri) /* noch mal versuchen?         */
  410.               (actsts == 1)? sconrq() : sdisrq(); /* ja                 */
  411.             else l4nsta(4);    /* Fehler melden                 */
  412.             }
  413.         } }
  414.       else {            /* Timeout ist schon 0                 */
  415.         if ((actsts == 2)    /* connectet und Frames unbestaetigt?         */
  416.           && ((fropen = (cirpoi->l4vs - cirpoi->l4rxvs) & 0xff) != 0)) {
  417.           for (tosend = 0, nxtfra = (mhtyp *) cirpoi->mbhdtx.lnext;
  418.              tosend < fropen;    /* Frames wiederholen                 */
  419.              ++tosend, nxtfra = (mhtyp *) nxtfra->link.lnext) {
  420.             if (--nxtfra->l4time == 0) { /* wenn Timeout abgelaufen         */
  421.               if (++nxtfra->l4trie < tratri) /* und noch Versuche frei         */
  422.                 sndfrm(nxtfra->pid, nxtfra);
  423.               else {
  424.                 l4nsta(4);    /* sonst melden                     */
  425.                 break;
  426.                 }
  427.               }
  428.             }
  429.           }
  430.         }
  431.       if (actsts == 2) {    /* connectet?                     */
  432.         if ((cirpoi->acktim != 0)
  433.           && (--cirpoi->acktim == 0)) /* ACK-Timer gerade abgelaufen?         */
  434.           sndack();        /* dann ACK senden                 */
  435.         if ((cirpoi->tranoa != 0)
  436.           && (--cirpoi->tranoa == 0)) /* No-activity-Timeout abgelaufen?     */
  437.           endcir();        /* dann abwerfen                 */
  438.         }
  439.   } }
  440. }
  441.  
  442. /*---------------------------------------------------------------------------*/
  443. VOID    newcir()        /* neuen Circuit aufbauen             */
  444.   {
  445.   clrcir();            /* Eintrag in CIRTAB loeschen             */
  446.   cirpoi->ideige = random();    /* eigenen ID erzeugen                 */
  447.   cirpoi->l4try = 0;        /* Versuche = 0                     */
  448.   sconrq();            /* Connect Request senden             */
  449.   cirpoi->state3 = 1;        /* neuer Status                     */
  450.   }
  451.  
  452. /*---------------------------------------------------------------------------*/
  453. VOID    discir()        /* Circuit aufloesen                 */
  454.   {
  455.   if ((cirpoi->state3 == 1)    /* Status CON-REQ?                 */
  456.     || (cirpoi->state3 == 3))    /* oder DIS-REQ?                 */
  457.     l4nsta(0);            /* nicht nach oben, nur intern melden         */
  458.  
  459.   else {            /* connectet:                     */
  460.     kilfra();            /* alle Fragmente loeschen             */
  461.     dealml(&cirpoi->mbhdrx);    /* empfangene Frames loesschen             */
  462.     cirpoi->numrx = 0;
  463.     cirpoi->l4flag |= 0x80;    /* Abwurf einleiten                 */
  464.     }
  465.   }
  466.  
  467. /*---------------------------------------------------------------------------*/
  468. BOOLEAN    itocir(cflg, mbhd)    /* Info an Circuit senden             */
  469. register mhtyp       *mbhd;    /* Message Header                 */
  470. unsigned cflg;            /* Congestion Flag                 */
  471.   {
  472.   register cirtyp *cblk;    /* Kontrollblock                 */
  473.  
  474.   if (((cblk = (cirtyp *) mbhd->l2lnk)->numtx < conctl)        /* Platz?    */
  475.     || (cflg == 1))                    /* immer senden?     */
  476.     {
  477.       relink(unlink(mbhd), cblk->mbhdtx.lprev);     /* Info umhaengen    */
  478.       ++cblk->numtx;                    /* Frames zaehlen    */
  479.       mbhd->morflg = 0;                    /* Frame komplett    */
  480.       cblk->tranoa = ininat;                /* Timeout neu         */
  481.       return(TRUE);                    /* hat funktioniert  */
  482.     }
  483.   else return(FALSE);                    /* Fehler, ging nicht*/
  484.   }
  485.  
  486. /*---------------------------------------------------------------------------*/
  487. VOID    clr4rx(cflg)        /* restliche Info senden             */
  488.   unsigned cflg;        /* Congestion Flag                 */
  489.   {
  490.   register mhtyp *mbhd;        /* Message Header                 */
  491.  
  492.   while (cirpoi->numrx != 0) {    /* ein Frame nach dem anderen             */
  493.     (mbhd = (mhtyp * )cirpoi->mbhdrx.lnext)->l2lnk = (l2ltyp *)cirpoi;
  494.     mbhd->usrtyp = 4;        /* User ist Circuit                 */
  495.     if (fmlink(cflg, mbhd) == 0) break; /* Ende bei Fehler             */
  496.     cirpoi->tranoa = ininat;    /* Timeout setzen                 */
  497.     --cirpoi->numrx;        /* ein Frame ist weg                 */
  498.     }
  499.   }
  500.  
  501. /*---------------------------------------------------------------------------*/
  502. VOID    chksts()        /* Status des eingelaufenen Frames auswerten */
  503.   {
  504.   register unsigned frofs;    /* bestaetigter Offset                 */
  505.   register unsigned fropen;    /* unbestaetigte Frames                 */
  506.  
  507.   if ((
  508.     fropen = (cirpoi->l4vs - cirpoi->l4rxvs) & 0xff
  509.     ) != 0) {            /* Frames offen?                 */
  510.     if ((
  511.       frofs = (l4hdr3 - cirpoi->l4rxvs) & 0xff /* neu bestaetigte Frames     */
  512.       ) != 0) {
  513.       if (frofs <= fropen) {
  514.         while (frofs-- != 0) {
  515.           dealmb(unlink(cirpoi->mbhdtx.lnext));   /* koennen weg         */
  516.           --cirpoi->numtx;    /* eins weniger zu senden             */
  517.           ++cirpoi->l4rxvs;    /* eins mehr bestaetigt                 */
  518.     } } } }
  519.   if ((l4opco & 0x80) == 0) {    /* Partner choked?                 */
  520.     cirpoi->l4flag &= 0xffdf;    /* nein: merken                     */
  521.     cirpoi->traout = 0;        /* Timeout kann nicht kommen             */
  522.     if (((l4opco & 0x40) != 0)    /* NAK Flag?                     */
  523.       && (cirpoi->l4vs != cirpoi->l4rxvs)) /* und noch was offen?         */
  524.       sndfrm(cirpoi->l4rxvs, cirpoi->mbhdtx.lnext);      /* dann wiederholen */
  525.     }
  526.   else {            /* Partner ist choked                 */
  527.     cirpoi->l4flag |= 0x20;    /* merken                     */
  528.     cirpoi->traout = trabsy;    /* warten                     */
  529.     cirpoi->l4vs = cirpoi->l4rxvs; /* keine Frames offen             */
  530.     }
  531.   }
  532.  
  533. /*---------------------------------------------------------------------------*/
  534. VOID    takfrm(mbhdp)        /* empfangenes Frame uebernehmen         */
  535. mhtyp     *mbhdp;
  536.   {
  537.   register mhtyp *mbhd;
  538.   register char  *nxt1;        /* naechstes Zeichen des ersten Teils         */
  539.   unsigned get1;        /* Getcount des ersten Teils             */
  540.   unsigned more;        /* Frame ist auch nur Fragment             */
  541.   register mhtyp *fragmn;    /* Fragment des Frames                 */
  542.  
  543.   mbhd = mbhdp;
  544.   if ((cirpoi->l4flag & 0x80) == 0) { /* liegt DISC-REQ vor?             */
  545.     if ((fragmn = cirpoi->fragme) == NULL) { /* noch kein Fragment vorhanden */
  546.       if (mbhd->morflg == 1) {    /* ist dies ein Fragment?             */
  547.         cirpoi->fragme = mbhd;    /* dann nur merken                 */
  548.         mbhd = NULL;        /* Frame ist weg                 */
  549.       } }
  550.     else {            /* Fragment schon vorhanden             */
  551.       nxt1 = fragmn->nxtchr;    /* altes Ende merken                 */
  552.       get1 = fragmn->getcnt;
  553.       while (fragmn->getcnt < fragmn->putcnt)
  554.         getchr(fragmn);        /* auf Ende des ertsen Teils gehen         */
  555. #ifdef MODIFIED
  556.       mhtyp_copy( mbhd, fragmn );
  557. #else
  558.       while (mbhd->getcnt < mbhd->putcnt)
  559.         putchr(getchr(mbhd), fragmn); /* neues Frame anhaengen             */
  560. #endif
  561.       fragmn->nxtchr = nxt1;    /* Pointer wieder auf alten Stand         */
  562.       fragmn->getcnt = get1;
  563.       more = mbhd->morflg;    /* kommt noch mehr?                 */
  564.       dealmb(mbhd);        /* neuer Teil kann weg                 */
  565.       if (more == 0) {        /* nichts mehr im Rohr?                 */
  566.         mbhd = fragmn;        /* dann ist das Ergebniss die neue Summe     */
  567.         cirpoi->fragme = 0;    /* kein Fragment mehr da             */
  568.         }
  569.       else mbhd = 0;        /* es kommt noch was: Fragment bleibt         */
  570.       }
  571.     if (mbhd != 0) {        /* Frame noch da?                 */
  572.       relink(mbhd, cirpoi->mbhdrx.lprev);      /* dann in RX Liste haengen   */
  573.       ++cirpoi->numrx;        /* ein Frame mehr da                 */
  574.       }
  575.     }
  576.   else {            /* Kanal soll abgeworfen werden             */
  577.     dealmb(mbhd);        /* Frame vernichten                 */
  578.     }
  579.   ++cirpoi->l4vr;        /* RX-Sequenz erhoehen                 */
  580.   }
  581.  
  582. /*---------------------------------------------------------------------------*/
  583. VOID    sndfrm(txsequ, mbhd)    /* Frame senden                     */
  584. register mhtyp     *mbhd;        /* Info                         */
  585. unsigned txsequ;        /* Sendesequenz fuer L4                 */
  586.   {
  587.   register char     *next;        /* Pointer auf letztes Zeichen des Headers   */
  588.   register mhtyp *netmhd;    /* Netzwerk MBHD                      */
  589.  
  590.   l4ahd2 =            /* VS in Netzwerkheader                 */
  591.   mbhd->pid = txsequ;        /* VS als PID                     */
  592.   l4aopc = 5;            /* Opcode = Info                 */
  593.   ackhdr();            /* Rest des Headers erzeugen             */
  594.   next =
  595.   (netmhd = gennhd())        /* Buffer fuer Netzwerkframe holen         */
  596.           ->nxtchr;        /* Position Opcode merken (eins davor)         */
  597.   if ((
  598. #ifdef MODIFIED
  599.     /* in modified form, allow big frames to be split
  600.      */
  601.     splcpy((256 - netmhd->putcnt), netmhd, mbhd, YES) /* Info umkopieren     */
  602. #else
  603.     splcpy((256 - netmhd->putcnt), netmhd, mbhd) /* Info umkopieren         */
  604. #endif
  605.     ) /*== 1*/) {        /* hat alles reingepasst?             */
  606.     ++cirpoi->numtx;        /* neun: ein Frame mehr                 */
  607.     mbhd->morflg = TRUE;    /* Fragmentierung markieren             */
  608.     }
  609.   if (mbhd->morflg == TRUE)
  610.     *(next -1) |= 0x20;        /* MORE Flag im Opcode setzen             */
  611.   itol3(netmhd);        /* Frame an Level3 liefern             */
  612.   mbhd->l4time = tratou;    /* Timeout im Infoframe setzen             */
  613.   }
  614.  
  615. /*---------------------------------------------------------------------------*/
  616. VOID    l4nsta(frtyp)        /* Statusaenderung in Level4             */
  617. char    frtyp;            /* als Reaktion auf : 0=intern, 1=UA, 2=DISC */
  618.   {                /* 3=DM, 4=L4-Versuche abgelaufen         */
  619.   clrcir();            /* alle Pointer im Eintrag loeschen         */
  620.   if (frtyp != 0) {        /* nach oben melden?                 */
  621.     l2tol7(frtyp, cirpoi, 4);    /* meldender User ist der Circuit         */
  622.     }
  623.   dealml(&cirpoi->mbhdrx);    /* keine Frames empfangen             */
  624.   dealml(&cirpoi->mbhdtx);    /* keine Frames zu senden             */
  625.   cirpoi->numrx =        /* Emfangsliste ist leer             */
  626.   cirpoi->numtx =        /* Sendeliste ist leer                 */
  627.   cirpoi->state3 = 0;        /* Status = Eintrag ist leer             */
  628.   }
  629.  
  630. /*---------------------------------------------------------------------------*/
  631. VOID    endcir()        /* Circuit aufloesen                 */
  632.   {
  633.     clrcir();            /* Eintrag in CIRTAB loeschen             */
  634.     cirpoi->l4try = 0;        /* Versuche ruecksetzen                 */
  635.     sdisrq();            /* Abwurf einleiten                 */
  636.     cirpoi->state3 = 3;        /* neuer Status: DISC-REQ gegeben         */
  637.   }
  638.  
  639. /*---------------------------------------------------------------------------*/
  640. VOID    clrcir()        /* Eintrag in CIRTAB loeschen             */
  641.   {
  642.   kilfra();            /* Fragmente loeschen                 */
  643.   dealml(&cirpoi->mbhdos);    /* Messageliste dafuer auch             */
  644.   cirpoi->l4rxvs =        /* alle Sequenzen auf 0                 */
  645.   cirpoi->l4vs =
  646.   cirpoi->l4vr =
  647.   cirpoi->l4rs =        /* ACK-NAK Flag                     */
  648.   cirpoi->traout =        /* Timeout                     */
  649.   cirpoi->l4flag = 0;        /* niemand choked, kein DISC-REQ         */
  650.   }
  651.  
  652. /*---------------------------------------------------------------------------*/
  653. VOID    sconrq()        /* CON-REQ senden                 */
  654.   {
  655.   register mhtyp *mbhd;        /* Buffer fuer Frame                 */
  656.  
  657.   l4pidx = cirpoi - &cirtab[0];    /* Index setzen                     */
  658.   l4pcid = cirpoi->ideige;    /* Partner und eigener Index             */
  659.   l4ahd2 =            /* zwei Bytes leer                 */
  660.   l4ahd3 = 0;
  661.   l4aopc = 1;            /* Opcode                     */
  662.   putchr (trawir, (mbhd = gennhd())); /* Rest des Headers             */
  663.   putfid(cirpoi->upcall, mbhd);    /* beide Calls in das Frame             */
  664.   putfid(myid, mbhd);
  665.   itol3(mbhd);            /* an Level3 liefern                 */
  666.   cirpoi->traout = tratou;    /* Timeout setzen                 */
  667.   }
  668.  
  669. /*---------------------------------------------------------------------------*/
  670. VOID    sdisrq()        /* DISC-REQ senden                 */
  671.   {
  672.   l4pidx = cirpoi->idxpar;    /* Index setzen                     */
  673.   l4pcid = cirpoi->idpart;    /* und ID                     */
  674.   l4ahd2 =            /* zwei Bytes leer                 */
  675.   l4ahd3 = 0;
  676.   l4aopc = 3;            /* Opcode                     */
  677.   itol3(gennhd());        /* Rest des Headers und dann an Level3         */
  678.   cirpoi->traout = tratou;    /* Timeout setzen                 */
  679.   }
  680.  
  681. /*---------------------------------------------------------------------------*/
  682. VOID    sndack()        /* ACK senden                     */
  683.   {
  684.   l4ahd2 = 0;
  685.   l4aopc = 6;            /* Opcode                     */
  686.   ackhdr();            /* Rest des Headers                 */
  687.   itol3(gennhd());        /* Rest des Headers und dann an Level3         */
  688.   }
  689.  
  690. /*---------------------------------------------------------------------------*/
  691. VOID    ackhdr()        /* ACK Header erzeugen                 */
  692.   {
  693.   l4pidx = cirpoi->idxpar;    /* Partner Index                 */
  694.   l4pcid = cirpoi->idpart;    /* Partner ID                     */
  695.   l4ahd3 = cirpoi->l4vr;    /* RX-Sequenz                     */
  696.   if ((cirpoi->l4flag & 0x40) != 0) /* selbst choked?                 */
  697.     l4aopc |= 0x80;        /* dann Flag setzen                 */
  698.   else {
  699.     if (cirpoi->l4rs == 1) {    /* wird es ein NAK Header?             */
  700.       l4aopc |= 0x40;        /* dann Flag setzen                 */
  701.       cirpoi->l4rs = 2;        /* NAK als gesendet markieren             */
  702.       }
  703.     }
  704.   cirpoi->acktim = 0;        /* ACK Timer ruecksetzen             */
  705.   }
  706.  
  707. /*---------------------------------------------------------------------------*/
  708. VOID    itol3(mbhd)        /* Info an Level3                 */
  709. register mhtyp    *mbhd;
  710.   {
  711.   mbhd->l2lnk = (l2ltyp *) cirpoi->l3node;    /* Controllblock         */
  712.   relink(mbhd, l3txl.lprev);    /* nur umhaengen                 */
  713. #ifdef STATSCMD
  714.   L4TXCNT[0]++;            /* bump tx count */
  715. #endif
  716.   }
  717.  
  718. /*---------------------------------------------------------------------------*/
  719. mhtyp    *gennhd()        /* Netzwerk Header erzeugen             */
  720.   {
  721.   register unsigned cnt;    /* Scratch Zaehler                 */
  722.   register mhtyp *mbhd;        /* Buffer fuer Info                 */
  723.  
  724.   mbhd = (mhtyp *) allocb();        /* Buffer besorgen             */
  725.   for (cnt = 15; cnt != 0; --cnt) /* die ersten 15 Bytes fuer den Header leer */
  726.     putchr(0, mbhd);
  727.   putchr(l4pidx, mbhd);        /* Transport Header schreiben             */
  728.   putchr(l4pcid, mbhd);
  729.   putchr(l4ahd2, mbhd);
  730.   putchr(l4ahd3, mbhd);
  731.   putchr(l4aopc, mbhd);
  732.  
  733.   return(mbhd);            /* Buffer wird zurueck gegeben             */
  734.   }
  735.  
  736. /*---------------------------------------------------------------------------*/
  737. VOID    kilfra()        /* Fragmente loeschen                 */
  738.   {
  739.   if (cirpoi->fragme != NULL) {      /* schon leer?                 */
  740.     dealmb(cirpoi->fragme);             /* Fragment loeschen             */
  741.     cirpoi->fragme = NULL;        /* Eintrag loeschen             */
  742.     }
  743.   }
  744.  
  745. /*- Ende Level 4 ------------------------------------------------------------*/
  746.  
  747. /*--------------------------------------------------------------------------
  748.  * This utility is used to audit level 4 connects and disconnects by
  749.  * copying the info to all level 6 ccp users
  750.  */
  751. #ifdef MANAGED
  752. l4audit( what )
  753. {
  754.     if( auditmask & 8 )
  755.         notify( L4audit, 6, cirpoi->downca, cirpoi->upcall, what, 2 );
  756. }
  757. #endif
  758.  
  759. /* **********************************************************************
  760.  * to save a bit of space and time, do this efficiently
  761.  */
  762.  
  763. #ifdef MODIFIED
  764. mhtyp_copy( from, to )
  765. register mhtyp *from, *to;
  766. {
  767.     register unsigned i = from->putcnt - from->getcnt;
  768.  
  769.     while( i-- )
  770.         putchr(getchr( from ), to ); 
  771. }
  772.  
  773. #endif
  774.  
  775.  
  776. #ifdef MODIFIED
  777. set_acktim()
  778. {
  779.     if( ( cirpoi->acktim = traack ) == 0 )
  780.         sndack();
  781. }
  782.  
  783. #endif
  784.